const zbList = function() {
    this.content = ''; //html字符串
    this.contentNode = null; //html DOM 节点

    //点击每一行的回调
    this.onClickRow = function () {
        console.log(this);
    }

    //支持点击事件, 每一行最右边有一个箭头
    this.tplClick =
        '<div class="zb-list" id="{list_id}">\
            <div class="item" id="{item_id}" list_id="{list_id}" params="{params}">\
                <div class="title">{title}</div>\
                <div class="body">\
                    <div class="desc">{desc}</div>\
                    <div class="action zb-icon-right-arrow">&nbsp;</div>\
                </div>\
            </div>\
        </div>';

    //不支持点击事件, 仅展示文字
    this.tplText =
        '<div class="zb-list" id="{list_id}">\
            <div class="item" id="{item_id}" list_id="{list_id}">\
                <div class="title">{title}</div>\
                <div class="body">\
                    <div class="desc">{desc}</div>\
                </div>\
            </div>\
        </div>';

    this.initCss = function() {
        let flag = document.getElementsByClassName('zb-list');
        if (!flag || flag.length === 0) {
            let style = document.createElement('style');
            style.innerText =
                '.hide{display:none}'+
                '.show{display:block}'+
                '.zb-icon-right-arrow {background-image: url(\'\'); background-size: 100% 100%; background-repeat: no-repeat;}' +
                '.zb-list {}' +
                '.zb-list .item {display: flex; flex-direction: row; justify-content: space-between; align-items: center; border-bottom: 1px solid #c8c8c8; margin: 3px 1px; padding:3px 2px;}' +
                '.zb-list .item .title {}' +
                '.zb-list .item .body {display: flex; flex-direction: row; justify-content: flex-start; align-items: center}' +
                '.zb-list .item .desc {flex-grow: 1; text-align: right; overflow: hidden; white-space: nowrap; text-overflow:ellipsis;font-size: 14px; color: #888888; padding-right: 5px;}' +
                '.zb-list .item .action {width: 18px;}' +
                ''
            ;

            let head = document.getElementsByTagName('head')[0];
            head.appendChild(style);
        }
    }

    this.getTpl = function (type) {
        switch (type) {
            case 'click':
                return this.tplClick;
            case 'text':
                return this.tplText;
            default:
                return this.tplClick;
        }
    }

    //初始化
    this.init = function(data, config){
        this.initCss();

        let list_type = config['list_type'] ? config['list_type'] : 'click';
        let list_id = config['list_id'];
        let node = '';
        let list_data = '';
        let tpl = this.getTpl(list_type);
        node = this.htmlToNode(tpl);
        list_data = [{list_id: list_id, item: data}];
        this.content = this.repeatNode(node, list_data);
        this.contentNode = this.htmlToNode(this.content);

        if (list_type === 'click') {
            let items = this.contentNode.getElementsByClassName('item');
            for (let i=0; i<items.length; i++) {
                items[i].addEventListener('click', this.onClickRow.bind(items[i]));
            }
        }
    }

    //更新描述
    this.updateDesc = function (id, str='') {
        document.getElementById(id).getElementsByClassName('desc')[0].innerText = str;
    }

    //追加item到列表中
    this.append = function(data, config) {
        let list = document.getElementById(config['list_id']);

        //获取item模板
        let list_type = config['list_type'] ? config['list_type'] : 'click';
        let tpl = this.getTpl(list_type);
        let node = this.htmlToNode(tpl);
        let str = node.getElementsByClassName('item')[0].outerHTML;

        //挨个组装, 并添加
        for (let i=0; i<data.length; i++) {
            data[i]['list_id'] = config['list_id'];
            let tmp_str = this.repeatString(str, [data[i]]);
            let tmp_node = this.htmlToNode(tmp_str);
            if (list_type === 'click') {
                tmp_node.addEventListener('click', this.onClickRow.bind(tmp_node));
            }

            list.append(tmp_node)
        }
    }

    //覆盖指定id的dom元素
    this.replaceNode = function (id){
        let old = document.getElementById(id);
        let parent = old.parentNode;
        parent.replaceChild(this.contentNode, old);
    }

    //更新指定id的内容
    this.updateNode = function (id) {
        let contentBox = document.getElementById(id);
        contentBox.innerHTML = '<div id="tmp_list"></div>';
        let tmp = document.getElementById('tmp_list');
        contentBox.replaceChild(this.contentNode, tmp);
    }

    //覆盖指定id的html标签
    this.replaceHtml = function (id) {
        let dom = document.getElementById(id);
        if (dom) {
            dom.outerHTML = this.content;
        }
    }

    //将json编码, 可以作为html标签的属性
    this.encodeObj = function (obj) {
        return encodeURIComponent(JSON.stringify(obj));
    }

    //解码
    this.decodeObj = function (str) {
        return JSON.parse(decodeURIComponent(str));
    }

    this.htmlToNode = function(html) {
        let div = document.createElement('div');
        div.innerHTML = html;
        return div.firstElementChild;
    }

    this.repeatString = function (tplDom, arr, func=null) {
        if (tplDom.length === 0) {
            this.error('字符串长度为空');
            return;
        }

        if (arr.length === 0) {
            this.error('数据为空');
            return tplDom;
        }

        let tpl = tplDom;
        let out = '';
        for (let i=0; i<arr.length; i++) {
            if (typeof func === 'function') {
                arr[i] = func(arr[i]);
            }
            let map = arr[i];
            let tmp = tpl;
            for (let j in map) {
                let re = new RegExp('{' + j + '}', 'g');
                tmp = tmp.replace(re, map[j]);
            }

            let re = new RegExp('{_idx}', 'g');
            tmp = tmp.replace(re, parseInt(i)+1);

            out += tmp;
        }

        return out;
    };

    /**
     * @param node HTML DOM节点, 注意不是string
     * @param arr json数组 注意是数组类型
     * @return string 返回HTML字符串, 注意不是DOM节点
     */
    this.repeatNode = function (node, arr) {
        let out = [];
        for (let i=0; i<arr.length; i++) {
            let tmp = node.outerHTML;
            tmp = tmp.replace(/\s/g, ' '); //去掉回车换行, 减少空白符

            let map = arr[i];

            //先渲染内层的数组
            for (let j in map) {
                if (map[j] instanceof Array) { //数组, 递归替换
                    let subNode = node.querySelector('.'+j);
                    if (subNode) {
                        let subHtml = this.repeatNode(subNode, map[j]); //递归
                        let subTpl = subNode.outerHTML.replace(/\s/g, ' ');
                        tmp = tmp.replace(subTpl, subHtml);
                    }
                }
            }

            //再渲染内层的对象
            for (let j in map) {
                if (map[j] instanceof Object && !(map[j] instanceof Array)) { //对象, 递归替换
                    let subNode = node.querySelector('.'+j);
                    if (subNode) {
                        let subHtml = this.repeatNode(subNode, [map[j]]); //递归
                        let subTpl = subNode.outerHTML.replace(/\s/g, ' ')
                        tmp = tmp.replace(subTpl, subHtml);
                    }
                }
            }

            //最后渲染外层的键值对/字符串
            for (let j in map) {
                if (typeof map[j] === 'string' || typeof map[j] === 'number') { //字符串, 直接替换
                    let re = new RegExp('{' + j + '}', 'g');
                    tmp = tmp.replace(re, map[j]);
                }
            }

            out.push(tmp);
        }

        return out.join('');
    }

    this.error = function (str){
        console.log('zbList Error: '+str)
    }

}

/**
 let mylist = new zbList();
 let config = {list_id:'mylist', list_type:''};
 let data = [
 {
        'item_id': '1111',
        'title':'测试-name1',
        'desc': '<p>Hello World!</p>',
        'params': 'xxx',
    },
 {
        'item_id': '2222',
        'title':'测试-name2',
        'desc': '<p>Hello World!</p>',
        'params': 'xxx',
    },
 ];
 mylist.onClickRow = function(){console.log(this)}
 mylist.init(data,config);

 //将id=content的节点替换为list
 mylist.replaceNode('content');

 let children = [
 {
        'item_id': '3333',
        'title':'测试-name3',
        'desc': '<p>Hello World!</p>',
        'params': 'xxx',
    },
 {
        'item_id': '4444',
        'title':'测试-name4',
        'desc': '<p>Hello World!</p>',
        'params': 'xxx',
    },
 ];
 mylist.append(children, config);
 */